<template>
  <div class="profile" :class="dark ? 'dark-theme' : 'light-theme'">
    <header>
      <div class="logo">
        <router-link to="/">
          <div class="logo-image" />
        </router-link>
        <div class="darkmode" @click="themeToggle()" />
      </div>
      <div class="search">
        <form @submit.prevent="search()">
          <label>github.com/</label>
          <input v-model="username" />
          <button type="submit">Search</button>
        </form>
      </div>
    </header>
    <div class="spinner" v-if="loading"></div>
    <transition name="fade">
      <div v-if="!showError&&!loading" class="main">
        <aside>
          <div class="about">
            <div class="dp">
              <img :src="profile.avatar_url" @click="themeToggle()" />
            </div>
            <div class="name">
              <h1>
                {{profile.name}}
                <a :href="profile.html_url" target="_blank">↗</a>
              </h1>
              <a :href="profile.blog">{{getBlog(profile.blog)}}</a>
            </div>
          </div>
          <div class="stats">
            <div class="item">
              <h3>Followers</h3>
              <p>{{profile.followers}}</p>
            </div>
            <div class="item">
              <h3>Following</h3>
              <p>{{profile.following}}</p>
            </div>
            <div class="item">
              <h3>Stars Received</h3>
              <p>{{getStars}}</p>
            </div>
            <div class="item">
              <h3>Forks by users</h3>
              <p>{{getForks}}</p>
            </div>
          </div>
          <div class="lang">
            {{getLanguages}}
            <span v-for="lang in languages" :key="lang">{{lang}}</span>
          </div>
          <div class="dates">
            <div class="joined">
              <h4>Joined</h4>
              <p>{{joinDate}}</p>
            </div>
            <div class="location">
              <h4>Location</h4>
              <p>{{profile.location}}</p>
            </div>
            <span>Last Updated on {{lastUpdateDate}}</span>
          </div>
        </aside>
        <section>
          <h2>Latest Activities</h2>
          <hr />
          <div class="activities">
            <div
              v-for="activity in activities"
              :key="activity.id"
              class="act"
              v-if="defineActivity(activity)"
            >
              <div v-html="defineActivity(activity)" class="entry"></div>
              <div class="time">{{convertToRelative(activity.created_at)}}</div>
            </div>
          </div>
        </section>
      </div>
    </transition>
    <transition name="fade">
      <div v-if="showError&&!loading" class="error">
        <div class="octocat">
          <img class="error-state" />
        </div>
        <div class="message">
          <h2>Username not found.</h2>
          <h3></h3>
        </div>
      </div>
    </transition>
    <transition name="fade">
      <Foot v-if="!showError&&!loading"></Foot>
    </transition>
  </div>
</template>

<script>
import axios from "axios";
import Foot from "./Foot.vue";
export default {
  name: "Profile",
  data() {
    return {
      profile: [],
      activities: [],
      repos: [],
      loading: true,
      showError: false,
      activityCount: 20,
      username: "",
      languages: [],
      dark: ""
    };
  },
  components: {
    Foot
  },
  mounted: function() {
    //get username from the route
    let user = this.$route.params.id;
    this.username = user;
    //make request to github API
    this.makeRequest(user);
    //fix back button on mobile
    window.onpopstate = event => {
      this.$router.push("/");
    };

    //set theme
    let temp = document.getElementById("app").className;
    if (temp == "light-theme") {
      this.dark = false;
    } else {
      this.dark = true;
    }
  },
  computed: {
    //get total stars
    getStars: function() {
      let totalStars = 0;
      this.repos.forEach(repo => {
        totalStars += repo.stargazers_count;
      });
      return totalStars;
    },
    //get total forks
    getForks: function() {
      let totalForks = 0;
      this.repos.forEach(repo => {
        totalForks += repo.forks_count;
      });
      return totalForks;
    },
    //get all the languages
    getLanguages: function() {
      let languages = [];
      this.repos.forEach(repo => {
        languages.push(repo.language);
      });
      this.languages = languages //remove repeating values
        .filter(function(elem, index, self) {
          return index == self.indexOf(elem);
        }) //remove null values
        .filter(Boolean);
    },
    //get join date of user after beautifying it
    joinDate: function() {
      return this.beautifyDate(this.profile.created_at);
    },
    //get last date of profile update after beautifying it
    lastUpdateDate: function() {
      return this.beautifyDate(this.profile.updated_at);
    },
    //get last time of profile update after beautifying it
    lastUpdateTime: function() {
      return this.beautifyTime(this.profile.updated_at);
    }
  },
  methods: {
    makeRequest: function(name) {
      //make request to github API
      this.loading = true;
      this.showError = false;
      axios
        .all([
          axios.get("https://api.github.com/users/" + name),
          axios.get(
            "https://api.github.com/users/" +
              name +
              "/events?per_page=" +
              this.activityCount
          ),
          axios.get(
            "https://api.github.com/users/" + name + "/repos?per_page=100"
          )
        ])
        .then(
          axios.spread((profile, activity, repo) => {
            //hide loader
            this.loading = false;

            //set data
            this.profile = profile.data;
            this.activities = activity.data;
            this.repos = repo.data;

            //append http if not
            if (!/^https?:\/\//i.test(this.profile.blog)) {
              this.profile.blog = "http://" + this.profile.blog;
            }
          })
        )
        .catch(err => {
          this.loading = false;
          console.log(err);
          this.showError = true;
        });
    },
    search: function() {
      let user = this.username;
      if (user) {
        this.$router.push("/" + user);
        this.makeRequest(user);
      } else {
        this.showError = true;
      }
    },
    //convert a date string to DD MM, YYYY Format
    beautifyDate: function(s) {
      return new Date(s).toLocaleDateString([], {
        month: "short",
        day: "numeric",
        year: "numeric"
      });
    },
    //convert a time string to HH:MM Format
    beautifyTime: function(t) {
      return new Date(t).toLocaleTimeString([], {
        hour: "2-digit",
        minute: "2-digit"
      });
    },
    //clean up blog text
    getBlog: function(a) {
      let remove = ["https://www.", "http://www.", "http://", "https://"];
      remove.forEach(x => {
        a.includes(x) ? (a = a.replace(x, "")) : "";
      });
      return a;
    },
    //changes url from api.github.com to standard form
    cleanURL: function(u) {
      return u.replace("api", "www").replace("/repos", "");
    },
    //convert time of activity to relative time
    convertToRelative: function(s) {
      //courtesy:https://stackoverflow.com/a/6109105
      let current = new Date();
      let previous = new Date(s);
      var msPerMinute = 60 * 1000;
      var msPerHour = msPerMinute * 60;
      var msPerDay = msPerHour * 24;
      var msPerMonth = msPerDay * 30;

      var elapsed = current - previous;

      if (elapsed < msPerMinute) {
        return Math.round(elapsed / 1000) + " seconds ago";
      } else if (elapsed < msPerHour) {
        return Math.round(elapsed / msPerMinute) + " minutes ago";
      } else if (elapsed < msPerDay) {
        let hours = Math.round(elapsed / msPerHour);
        if (hours == 1) {
          return hours + " hour ago";
        } else {
          return hours + " hours ago";
        }
      } else if (elapsed < msPerMonth && Math.round(elapsed / msPerDay) <= 2) {
        let days = Math.round(elapsed / msPerDay);
        if (days == 1) {
          return days + " day ago";
        } else {
          return days + " days ago";
        }
      } else {
        //dont convert if older than 2 days
        return previous.toLocaleDateString([], {
          month: "short",
          day: "numeric"
        });
      }
    },
    //defining events
    defineActivity: function(activity) {
      let stmnt,
        repoURL,
        starIcon,
        createIcon,
        commentIcon,
        deleteIcon,
        forkIcon;
      //set repo url for referencing
      repoURL =
        '<a href="' +
        this.cleanURL(activity.repo.url) +
        '">' +
        activity.repo.name +
        "</a>";
      createIcon =
        '<img class="icon" src=""/>';
      commentIcon =
        '<img class="icon" src=""/>';
      deleteIcon =
        '<img class="icon" src=""/>';
      forkIcon =
        '<img class="icon" src=""/>';
      starIcon =
        '<img class="icon" src=""/>';
      switch (activity.type) {
        case "PushEvent":
          //say pushed 1 commit in case of single commit, otherwise say commits
          let commit = "commit";
          if (activity.payload.size > 1) {
            commit += "s";
          }
          //if event is pushed
          // ref starts with "refs/heads/"
          let branchRef = activity.payload.ref.slice(11);
          stmnt =
            createIcon +
            "Pushed " +
            activity.payload.size +
            " " +
            commit +
            " to " +
            '<a href="' +
            this.cleanURL(activity.repo.url) +
            "/tree/" +
            branchRef +
            '">' +
            branchRef +
            "</a>" +
            " in " +
            repoURL;
          break;
        case "WatchEvent":
          stmnt = starIcon + "Starred a repo " + repoURL;
          break;
        case "CreateEvent":
          if (activity.payload.ref_type === "branch") {
            stmnt = forkIcon;
          } else {
            stmnt = createIcon;
          }
          stmnt += "Created a " + activity.payload.ref_type + " ";
          if (activity.payload.ref_type === "branch") {
            stmnt +=
              '<a href="' +
              this.cleanURL(activity.repo.url) +
              "/tree/" +
              activity.payload.ref +
              '">' +
              activity.payload.ref +
              "</a>" +
              " in " +
              repoURL;
          } else {
            stmnt += repoURL;
          }
          break;
        case "DeleteEvent":
          stmnt =
            deleteIcon +
            "Deleted a " +
            activity.payload.ref_type +
            " " +
            activity.payload.ref +
            " from " +
            repoURL;
          break;
        case "ForkEvent":
          stmnt =
            forkIcon +
            "Forked a repo " +
            repoURL +
            " to " +
            '<a href="' +
            activity.payload.forkee.html_url +
            '">' +
            activity.payload.forkee.full_name +
            "</a>";
          break;
        case "PullRequestEvent":
          if (activity.payload.action === "closed") {
            stmnt = deleteIcon;
          } else {
            stmnt = createIcon;
          }
          stmnt +=
            activity.payload.action.charAt(0).toUpperCase() +
            activity.payload.action.slice(1) +
            " a " +
            '<a href="' +
            activity.payload.pull_request.html_url +
            '">' +
            " pull request " +
            "</a>" +
            " in " +
            repoURL;
          break;
        case "PullRequestReviewCommentEvent":
          stmnt =
            commentIcon +
            activity.payload.action.charAt(0).toUpperCase() +
            activity.payload.action.slice(1) +
            " a " +
            '<a href="' +
            activity.payload.comment.html_url +
            '">' +
            "comment" +
            "</a>" +
            " on their pull request in " +
            repoURL;
          break;
        case "IssuesEvent":
          if (activity.payload.action === "closed") {
            stmnt = deleteIcon;
          } else {
            stmnt = createIcon;
          }
          stmnt +=
            activity.payload.action.charAt(0).toUpperCase() +
            activity.payload.action.slice(1) +
            " an " +
            '<a href="' +
            activity.payload.issue.html_url +
            '">' +
            " issue " +
            "</a>" +
            " in " +
            repoURL;
          break;
        case "IssueCommentEvent":
          stmnt =
            commentIcon +
            activity.payload.action.charAt(0).toUpperCase() +
            activity.payload.action.slice(1) +
            " " +
            '<a href="' +
            activity.payload.comment.html_url +
            '">' +
            "a comment" +
            "</a>" +
            " on an issue in " +
            repoURL;
          break;
        default:
          return false;
          break;
      }
      return stmnt;
    },
    setDark: function() {
      document.body.style.backgroundColor = "#1a1c21";
      document.getElementById("app").className = "dark-theme";
      //favicon
      document.querySelector("link[rel='shortcut icon']").href =
        "./static/favicon-light.png";
      document.querySelector("link[rel*='icon']").href =
        "./static/favicon-light.png";
    },
    setLight: function() {
      document.body.style.backgroundColor = "#fdfdfd";
      document.getElementById("app").className = "light-theme";
      //favicon
      document.querySelector("link[rel='shortcut icon']").href =
        "./static/favicon-dark.png";
      document.querySelector("link[rel*='icon']").href =
        "./static/favicon-dark.png";
    },
    themeToggle: function() {
      let vm = this;
      if (vm.dark) {
        vm.dark = false;
        localStorage.setItem('current-theme', 'light');
        vm.setLight();
      } else {
        vm.dark = true;
        localStorage.setItem('current-theme', 'dark');
        vm.setDark();
      }
    }
  }
};
</script>

<style scoped lang="scss">
</style>
